from pydantic import BaseModel, validator, field_validator
from typing import List, Union
from fastapi import APIRouter
from fastapi.templating import Jinja2Templates
from fastapi import Request
from fastapi.exceptions import HTTPException
from models import *

student = APIRouter()

class StudentIn(BaseModel):
    name: str
    pwd: str
    student_number: int
    class_name_id: int
    courses: List[int] = []

    @field_validator("name")
    def name_must_alpha(cls, value):
        assert value.isalpha(), 'name must be alpha'
        return value

    @field_validator("student_number")
    def student_number_validate(cls, value):
        assert 1000 < value < 30000, '学号要在2000-10000的范围内'
        return value


@student.get("/")
async def getAllStudent():
    student_list = await Student.all() # QuerySet: [Student(), Student(), Student()]
    print("student_list: ", student_list)

    for student in student_list:
        print(student.name, student.student_number)

    # 查询所有class_room_id为1的学生
    query_class_student_list = await Student.filter(class_name_id=1)
    print("query_class_student_list: ", query_class_student_list)

    # 查询指定姓名的学生
    student = await Student.filter(name="rain")
    print("student: ", student)

    # 模糊查询 - student_number大于20001
    student_list = await Student.filter(student_number__gt=20001)
    student_list = await Student.filter(student_number__range=[1, 10001])
    student_list = await Student.filter(student_number__in=[10001, 10003])
    print("student_list: ", student_list)

    # values查询
    student_list = await Student.filter(student_number__range=[1, 100001])

    # values查询取值
    student_list = await Student.all().values("id", "name", "student_number")
    print("student_list: ", student_list)

    return {"操作": "查看所有的学生"}

@student.get("/index.html")
async def getAllStudent(request: Request):
    templates = Jinja2Templates(directory="templates")
    student_list = await Student.all()  # [Student(),Student(),...]

    return templates.TemplateResponse(
        "index.html", {
            "request": request,
            "student_list": student_list
        }
    )


@student.post("/")
async def addStudent(student_in: StudentIn):
    # 插入到数据库
    # 方式1
    # student = Student(name=student_in.name, pwd=student_in.pwd, student_number=student_in.student_number, class_name_id=student_in.class_name_id)
    # await student.save() # 插入到数据库student表

    # 方式2
    student = await Student.create(name=student_in.name, pwd=student_in.pwd, student_number=student_in.student_number, class_name_id=student_in.class_name_id)

    # 多对多的关系绑定
    choose_courses = await Course.filter(id__in=student_in.courses)
    await student.courses.add(*choose_courses)

    return student

@student.get("/{student_id}")
async def getOneStudent(student_id: int):
    student = await Student.get(id=student_id)
    print("student: ", student)
    print("student.name: ", student.name)
    print("student.student_number: ", student.student_number)
    print("student.class_name: ", student.class_name)
    print("student.courses: ", student.courses)

    # 获取学生关联专业信息, 获取专业的具体名称
    class_name_obj = await student.class_name
    print("student.class_name.id", class_name_obj.id)
    print("student.class_name.name", class_name_obj.name)

    print("第二种获取方法：student.class.values('name'): ", await student.class_name.values('name'))
    students = await Student.all().values("name", "class_name__name")
    print("students: ", students)

    print(await student.courses.all().values("name", "teacher__name"))
    print(await Student.all().values("name", "class_name__name", "courses__name"))

    # 通过已知的学生对象进行多对多关联查询
    course_obj = await student.courses
    print("course_obj: ", course_obj)

    for course in course_obj:
        print("course.id: ", course.id)
        print("course.name: ", course.name)
        print("course.class_addr: ", course.class_addr)

        teacher_obj = await course.teacher
        print("teacher_obj: ", teacher_obj)
        print("teacher_obj.id: ", teacher_obj.id)
        print("teacher_obj.name: ", teacher_obj.name)

@student.put("/{student_id}")
async def updateStudent(student_id: int, student_in: StudentIn):
    data = student_in.dict()
    print("data: ", data)
    courses = data.pop("courses")

    await Student.filter(id=student_id).update(**data)

    # 设置多对多的选修课程
    student = await Student.get(id=student_id)
    choose_courses = await Course.filter(id__in=courses)
    await student.courses.clear()
    await student.courses.add(*choose_courses)

    return {"操作": "更新id={student_id}的学生信息"}

@student.delete("/{student_id}")
async def deleteStudent(student_id: int):
    delete_count = await Student.filter(id=student_id).delete()
    if not delete_count:
        raise HTTPException(status_code=404, detail=f"主键为{student_id}的学生不存在")

    return {}